﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.WindowsAPICodePack.Shell;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;

namespace Kay.Music.Attribute
{
    public class MediaObject
    {
        public string MediaPath { get; set; }

        public MediaTags Tags { get; set; }

        public MediaTags OldTags { get; set; }

        public MediaObject(string path)
        {
            if (path == null) throw new ArgumentNullException(nameof(path));
            if(!File.Exists(path)) throw new ArgumentException(nameof(path));
            MediaPath = path;
            Tags = new MediaTags();
            InitTags();
            OldTags = Tags;
        }

        private void InitTags()
        {
            using (var obj = ShellObject.FromParsingName(MediaPath))
            {
                var mediaInfo = obj.Properties;
                foreach (var propertyInfo in Tags.GetType().GetProperties())
                {
                    var mp3Att =
                        propertyInfo.GetCustomAttributes(typeof(MediaPropertyAttribute), false).FirstOrDefault();
                    var shellProperty = mediaInfo.GetProperty("System." + mp3Att);
                    var value = shellProperty?.ValueAsObject;
                    if (value == null) continue;
                    else if(shellProperty.ValueType==typeof(string[]))
                    {
                        propertyInfo.SetValue(Tags, string.Join(";", value as string[]), null);
                    }
                    else if (propertyInfo.PropertyType != shellProperty.ValueType)
                    {
                        propertyInfo.SetValue(Tags,
                            shellProperty.FormatForDisplay(PropertyDescriptionFormatOptions.None), null);
                    }
                    else
                    {
                        propertyInfo.SetValue(Tags, value, null);
                    }
                }
            }
        }

        public void Commit()
        {
            using (var obj = ShellObject.FromParsingName(MediaPath))
            {
                var mediaInfo = obj.Properties;
                foreach (var proper in Tags.GetType().GetProperties())
                {
                    var oldValue = proper.GetValue(OldTags, null);
                    var newValue = proper.GetValue(Tags, null);

                    if (oldValue == null && newValue == null)
                    {
                        continue;
                    }
                    if (oldValue != null && oldValue.Equals(newValue)) continue;
                    var mp3Att = proper.GetCustomAttributes(typeof(MediaPropertyAttribute), false).FirstOrDefault();
                    var shellProper = mediaInfo.GetProperty("System." + mp3Att);
                    //Console.WriteLine(mp3Att);
                    SetPropertyValue(shellProper, newValue);
                }
            }
        }

        private void SetPropertyValue(IShellProperty prop, object value)
        {
            if (prop.ValueType == typeof(string[]))
            {
                var s = value as string;
                if (s == null) return;
                var values = s.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                var shellProperty = prop as ShellProperty<string[]>;
                if (shellProperty != null) shellProperty.Value = values;
            }
            else if(prop.ValueType == typeof(string))
            {
                var shellProperty = prop as ShellProperty<string>;
                if (shellProperty != null) shellProperty.Value = value as string;
            }
            else if (prop.ValueType == typeof(ushort?))
            {
                var shellProperty = prop as ShellProperty<ushort?>;
                if (shellProperty != null) shellProperty.Value = value as ushort?;
            }
            else if (prop.ValueType == typeof(short?))
            {
                var shellProperty = prop as ShellProperty<short?>;
                if (shellProperty != null) shellProperty.Value = value as short?;
            }
            else if (prop.ValueType == typeof(uint?))
            {
                var shellProperty = prop as ShellProperty<uint?>;
                if (shellProperty != null) shellProperty.Value = value as uint?;
            }
            else if (prop.ValueType == typeof(int?))
            {
                var shellProperty = prop as ShellProperty<int?>;
                if (shellProperty != null) shellProperty.Value = value as int?;
            }
            else if (prop.ValueType == typeof(ulong?))
            {
                var shellProperty = prop as ShellProperty<ulong?>;
                if (shellProperty != null) shellProperty.Value = value as ulong?;
            }
            else if (prop.ValueType == typeof(long?))
            {
                var shellProperty = prop as ShellProperty<long?>;
                if (shellProperty != null) shellProperty.Value = value as long?;
            }
            else if (prop.ValueType == typeof(DateTime?))
            {
                var shellProperty = prop as ShellProperty<DateTime?>;
                if (shellProperty != null)
                    shellProperty.Value = value as DateTime?;
            }
            else if (prop.ValueType == typeof(double?))
            {
                var shellProperty = prop as ShellProperty<double?>;
                if (shellProperty != null) shellProperty.Value = value as double?;
            }
        }
    }
}
